/**
 * @name: AliOssUpload
 * @description: 阿里oss直传
 * @upTime: 2023--02--06
 * @props { bool }      disabled        是否显示上传控件
 * @props { number }    len             上传数量
 * @props { string }    label           上传按钮文字
 * @props { func }      getFileResult   图片上传回调
 * @props { string }    type            上传列表的内建样式，支持三种基本样式 text, picture 和 picture-card
 * @props { string }    fileType        上传的文件格式     - 可选 video||image
 * @props { number }    maxSize         上传的文件大小     - 单位M
 * @props { array }     accept          控制上传的文件类型集合
 * @props { bool }      isShowRemoveIcon是否显示删除icon按钮
 * @props { array }     fileList        现有数据集合
 *
 **/

import React, { useRef } from 'react'
import PropTypes from 'prop-types'
import { Upload, Modal, Tooltip } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import { getBase } from '@/utils/getBase'
import OSS from "ali-oss"
import { HTML5Backend } from "react-dnd-html5-backend";
import { DndProvider, useDrag, useDrop } from 'react-dnd';
import update from "immutability-helper";
import './style.scss'

const type = 'DragableUploadList';
const DragableUploadListItem = ({ originNode, moveRow, file, fileList, isDrop }) => {
    const ref = useRef(null);
    const index = fileList.indexOf(file);
    const [{ isOver, dropClassName }, drop] = useDrop({
        accept: type,
        collect: (monitor) => {
            const { index: dragIndex } = monitor.getItem() || {};
            if (dragIndex === index) {
                return {};
            }
            return {
                isOver: monitor.isOver(),
                dropClassName: dragIndex < index ? ' drop-over-downward' : ' drop-over-upward',
            };
        },
        drop: (item) => {
            moveRow(item.index, index);
        },
    });
    const [, drag] = useDrag({
        type,
        item: {
            index,
        },
        collect: (monitor) => ({
            isDragging: monitor.isDragging(),
        }),
    });
    drop(drag(ref));
    const errorNode = <Tooltip title="Upload Error">{originNode.props.children}</Tooltip>;
    if (isDrop){
        return (
            <div
                ref={ref}
                className={`ant-upload-draggable-list-item ${isOver ? dropClassName : ''}`}
                style={{
                    cursor: 'move',
                }}
            >
                {file.status === 'error' ? errorNode : originNode}
            </div>
        );
    }else {
        return file.status === 'error' ? errorNode : originNode
    }
};

const ossConfig = {
    accessKeyId: "LTAI5tBXbDzPLVaYPFpeq3jK",
    accessKeySecret: "NNpMLWJv91EFjizPtPzFzXKaZDNjVu",
    // stsToken: res.security_token,
    region: "oss-cn-beijing",
    bucket: "hqmimage",
}

class TheUpload extends React.Component {
    state = {
        previewVisible: false,
        previewImage: '',
        previewTitle: '',
        fileList: [],
        previewType: 'image'
    };

    componentDidUpdate(prev) {
        if (prev.fileList.length !== this.props.fileList.length) {
            this.setState({ fileList: this.props.fileList })
        }
    }

    componentDidMount() {
        if (this.props.fileList) {
            this.setState({ fileList: this.props.fileList })
        }
    }

    handleCancel = () => this.setState({ previewVisible: false });
    handleRemove = (file) => {
        const index = this.state.fileList.indexOf(file)
        this.state.fileList.splice(index, 1)
        this.setState({
            fileList: this.state.fileList
        }, () => {
            this.props.getFileResult(this.state.fileList)
        })
    }

    handleChange = ({ file, fileList, event }) => {
        // if (file && fileList && fileList.length) {
        //     fileList = fileList.map(v => {
        //         console.log(v)
        //         if (v.status === 'done' && v.response) {
        //             if (v.response && v.response.code === 200 && v.response.data) {
        //                 return {...v}
        //             } else {
        //                 return {
        //                     ...v,
        //                     status: 'error'
        //                 }
        //             }
        //         } else if (v.status === 'error') {
        //             return {
        //                 response: v.response,
        //                 size: v.size,
        //                 uid: '-5',
        //                 name: v.name,
        //                 status: 'error',
        //             }
        //         } else {
        //             return {...v}
        //         }
        //     })
        // }
        this.props.getFileResult(fileList)
        this.setState({ fileList })
    };

    handlePreview = async file => {
        const type = this.getFileType(file.type || file.url)
        if (!file.url && !file.preview) {
            file.preview = await getBase(file.originFileObj);
        }
        let preview = {
            previewTitle: file.name || file.url.substring(file.url.lastIndexOf('/') + 1),
            previewType: type,
            previewImage: file.url || file.preview,
            previewVisible: true,
        }
        if (type === 'video') {
            // let url = file.url
            // if (url && url.includes('?')) {
            //     url = url.split("?")[0]
            // }
            preview.previewImage = file.url || file.response.data
        }
        await this.setState({
            ...preview
        })
    };
    handlePreviewFile = async (file) => {
        // 将图片转换为base64格式并返回一个Promise对象
        return new Promise((resolve) => {
            // 获取预览图片
            fetch(this.state.previewImage)
                // 将响应转换为Blob对象
                .then((response) => response.blob())
                // 读取Blob对象并将其转换为base64格式
                .then((blob) => {
                    const reader = new FileReader();
                    reader.onload = () => resolve(reader.result);
                    reader.readAsDataURL(blob);
                });
        });
        // const that = this
        // const fileType = this.getFileType(file.type)
        // return new Promise((resolve) => {
        //     const reader = new FileReader();
        //     reader.readAsDataURL(file);
        //     reader.onload = function (e) {
        //         const dataUrl = e.target.result;
        //         if (fileType === 'video') {
        //             resolve(that.getVideoCover(e.target.result))
        //         } else {
        //             resolve(dataUrl)
        //         }
        //     }
        // })
    }

    // 获取视频封面
    getVideoCover = (src) => {
        return new Promise((resolve, reject) => {
            let video = document.createElement("video");
            video.setAttribute("src", src);
            video.setAttribute("autoplay", "autoplay");
            video.setAttribute("crossOrigin", "anonymous"); //设置跨域 否则toDataURL导出图片失败
            video.setAttribute("width", "300"); //设置大小，如果不设置，下面的canvas就要按需设置
            video.setAttribute("height", "200");
            video.currentTime = 1; //视频时长，一定要设置，不然大概率白屏
            video.addEventListener("loadeddata", function () {
                let canvas = document.createElement("canvas"),
                    width = video.width, //canvas的尺寸和图片一样
                    height = video.height;
                canvas.width = width; //画布大小，默认为视频宽高
                canvas.height = height;
                canvas.getContext("2d").drawImage(video, 0, 0, width, height); //绘制canvas
                let dataURL = canvas.toDataURL("image/png"); //转换为base64
                resolve(dataURL);
            });
        });
    }

    getFileType(str) {
        if (str.indexOf('video') > -1) {
            return 'video'
        } else {
            return 'image'
        }
    }

    getFilename = (file) => {
        const idx = file.name.lastIndexOf('.')
        let ext = '', rdmString = ''
        if (idx !== -1) {
            ext = file.name.substr(idx)
        }
        for (; rdmString.length < 25; rdmString += Math.random().toString(36).slice(2));
        rdmString = rdmString.slice(0, 25)
        return `web_${new Date().getTime()}${rdmString}${ext}`
    }
    customRequest = (option) => {
        const { file, onProgress, onSuccess, onError } = option
        const filename = this.getFilename(file)
        const partSize = 1024 * 1024 * 15; // 每个分片大小(byte)
        const parallel = 1; // 同时上传的分片数
        const AliClient = new OSS(ossConfig)
        return new Promise((resolve, reject) => {
            AliClient
                .multipartUpload(
                    filename,
                    file,
                    {
                        parallel,
                        partSize,
                        progress: async (percent) => {
                            onProgress({ percent: percent * 100 })
                        },
                    }
                )
                .then((result) => {
                    const ossPath = result.res.requestUrls[0].split('?')[0]
                    const url = ossPath.replace(/^http:\/\//i, 'https://')
                    const data = {
                        code: result?.res?.status,
                        name: result?.name,
                        data: url,
                    }
                    const type = this.getFileType(file.type || file.url)
                    if (type === 'video') {
                        this.setState({
                            previewImage: url + "?x-oss-process=video/snapshot,t_1000,m_fast"
                        })
                    }
                    else {
                        this.setState({
                            previewImage: url
                        })
                    }
                    onSuccess(data)
                    resolve(result)
                })
                .catch((error) => {
                    onError(error)
                    reject(error)
                })
        })
    }

    moveRow = (dragIndex, hoverIndex) => {
        let { fileList } = this.state
        const dragRow = fileList[dragIndex];
        this.setState({
            fileList: update(fileList, {
                $splice: [
                    [dragIndex, 1],
                    [hoverIndex, 0, dragRow],
                ],
            }),
        }, () => {
            this.props.getFileResult(this.state.fileList)
        })
    }

    render() {
        const { previewVisible, previewImage, fileList, previewTitle, previewType } = this.state;
        const {
            len,
            disabled,
            label,
            type,
            fileType,
            maxSize,
            accept,
            isShowRemoveIcon,
            isDrop
        } = this.props;
        const uploadButton = (
            <div>
                <PlusOutlined />
                <div style={{ marginTop: 8 }}>{label}</div>
            </div>
        );
        const checkFileSize = (file) => {
            if (fileType && !['video', 'image'].includes(fileType)) {
                React.$message({
                    type: 'warning',
                    content: `fileType字段类型错误,仅支持image/video类型`
                })
                return Upload.LIST_IGNORE;
            }
            if (!accept.filter(item => item.indexOf(fileType) !== -1).includes(file.type)) {
                let mess = []
                // eslint-disable-next-line array-callback-return
                accept.filter(item => {
                    if (item.indexOf(fileType) !== -1) {
                        mess.push(item.replace(new RegExp(`${fileType}/`, 'g'), '.'))
                    }
                })
                React.$message({
                    type: 'warning',
                    content: `${file.name} 不是 ${mess} 类型文件`
                })
                return Upload.LIST_IGNORE;
            }
            if (file.size / 1024 / 1024 < (maxSize || 5)) {
                return true
            } else {
                React.$message({
                    type: 'info',
                    content: `文件最大不能超过${(maxSize || 5)}M`
                })
                return Upload.LIST_IGNORE;
            }
        };
        return (
            <DndProvider backend={HTML5Backend}>
                <Upload
                    listType={type}
                    multiple={true}
                    maxCount={len}
                    fileList={fileList}
                    accept={accept.toString()}
                    beforeUpload={checkFileSize}
                    onPreview={this.handlePreview}
                    previewFile={(e) => this.handlePreviewFile(e)}
                    onRemove={this.handleRemove}
                    onChange={this.handleChange}
                    showUploadList={{ showRemoveIcon: isShowRemoveIcon }}
                    customRequest={(option) => this.customRequest(option)}
                    itemRender = {(originNode, file, currFileList) => (
                        <DragableUploadListItem
                            originNode={originNode}
                            file={file}
                            fileList={currFileList}
                            moveRow={this.moveRow}
                            isDrop={isDrop}
                        />
                    )}
                >
                    {(fileList.length >= len || disabled) ? null : uploadButton}
                </Upload>
                <Modal
                    visible={previewVisible}
                    title={previewTitle}
                    footer={null}
                    onCancel={this.handleCancel}>
                    {
                        previewType === 'image' ? <img alt="example" style={{ width: '100%' }} src={previewImage} /> :
                            <video src={previewImage.split("?")[0]} style={{ width: '100%' }} controls></video>
                    }
                </Modal>
            </DndProvider>
        );
    }
}

TheUpload.propTypes = {
    disabled: PropTypes.bool,
    len: PropTypes.number,
    label: PropTypes.string,
    getFileResult: PropTypes.func,
    type: PropTypes.string,
    fileType: PropTypes.string,
    maxSize: PropTypes.number,
    accept: PropTypes.array,
    isShowRemoveIcon: PropTypes.bool,
    fileList: PropTypes.array,
    isDrop: PropTypes.bool,
}
TheUpload.defaultProps = {
    disabled: false,
    len: 5,
    label: 'Upload',
    type: 'picture-card',
    fileType: 'image',
    maxSize: 5,
    accept: ['image/jpg', 'image/jpeg', 'image/png', 'image/webp', 'image/svg+xml', 'video/mp4'],
    isShowRemoveIcon: true,
    fileList: [],
    isDrop: false
}
export default TheUpload
